
/*****************************************************************************\
 *                              Hand.cpp
\*****************************************************************************/

/*! @file 
 *
 *  @brief
 *
 *  @author Weiyu Yi, inweiyu@googlemail.com
 */

//---------------------------------------------------------------------------
//  Includes
//---------------------------------------------------------------------------

#include <defEException.h>
#include "Hand.h"

namespace vhand
{

//***************************************************************************
//                               Hand
//***************************************************************************

Hand::Hand()
:
    _drawSkin( true ),
    _drawBones( true ),
    _drawVolume( true )
{
}


Hand::~Hand()
{
    // the total release process will be complemented later
    // release host memory

    // release device memory
}


void Hand::initHost()
{
    ///////////////////////////////////////////////////////////////////////////////////
    // mapping the skin and spheres to its corresponding limb
    //

    const SphereTopology &_topo = *(_volumehandle.getSphereTopology());
    // 1) for spheres
    for ( unsigned int i=0; i < _topo.getAllAdjacency()->size(); i ++ )
    {
        const Adjacency &adjc = (*_topo.getAllAdjacency())[i];
        if ( adjc.getType() == MAP_SPHERE_BONES )
        {
            (*_armature.editSpheresToLimb())[ adjc.getOut() ] = _armature.getBonesToLimb()->find( adjc.getIn() )->second;
        }
    }
    _armature.makeLimbSpheresRef();

    // 2) for skin
    for ( unsigned int i=0; i < _topo.getAllAdjacency()->size(); i ++ )
    {
        const Adjacency &adjc = (*_topo.getAllAdjacency())[i];
        if ( adjc.getType() == MAP_SKIN_SPHERE )
        {
            (*_armature.editSkinToLimb())[ adjc.getOut() ] = _armature.getSpheresToLimb()->find( adjc.getIn() )->second;
        }
    }
    _armature.makeLimbSkinRef();

    return;
}


void Hand::initDevice( bool main_memory_preserve/* = true */ )
{
    ///////////////////////////////////////////////////////////////////////////////////
    // initial the object
    //
    _bones_geom.buildVBO( main_memory_preserve );
    _skin_geom.buildVBO( main_memory_preserve );
    _volumehandle.initDevice();

    // debug...
    _volumehandle.initGeometry();

    return;
}


void Hand::draw( void ) const
{
    printf( "Hand :: draw\n" );

    // draw bones
    if ( _drawBones )
    {
        _bones_geom.draw();
    }
    // draw volume
    if ( _drawVolume )
    {
        //_volumehandle.draw();
    }
    // draw skin
    if ( _drawSkin )
    {
        _skin_geom.draw();
    }

    // debug...
    _volumehandle.draw();
}


/** Update the limb transformation matrix
 * 
 * @param std::string   The name of the limb
 * @param limbmat       The transformation matrix of limb wrt. parent limb
 */
void Hand::moveLimb( std::string limbname, const Matrix4& limbmat )
{
    printf( "Hand : moveLimb\n" );

    // rigid transformation first
    // then run the mass-spring system simulation
    //
    // 1) get the global transformation matrix of the given limb
    // todo...
    _armature.moveLimb( limbname, limbmat );
    Matrix4 globallimbmat = _armature.getUpdateMatrix();

    //// debug...
    //printf( "localmat:\n" );
    //print( limbmat );
    //printf( "globalmat:\n" );
    //print( globallimbmat );

    const IndexRanges *rs_bones = _armature.getBonesUpdateRange();
    const IndexRanges *rs_skin = _armature.getSkinUpdateRange();
    const IndexRanges *rs_spheres = _armature.getSpheresUpdateRange();

    // 2) transform the limb including soft-simulation
    _volumehandle.deformation( rs_bones,
                               rs_skin,
                               rs_spheres,
                               globallimbmat );

    return;
}


void Hand::simulation()
{
    _volumehandle.simulation();
}


void Hand::updateGeometry()
{
    _volumehandle.updateGeometry();
}

} // namespace vhand
